package br.requisiteworks.modelo.dao.jpa;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;
import javax.persistence.TypedQuery;

import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import br.requisiteworks.modelo.Cliente;
import br.requisiteworks.modelo.dao.ClienteDao;
import br.requisiteworks.util.persistencia.ErroBancoDados;
import br.requisiteworks.util.persistencia.ResultadoVazio;

/**
 * Implementacao JPA do {@link ClienteDao}
 * 
 * @author Mikhail Domanoski
 * 
 * @version 3, 26/05/2010
 * 
 */
@Repository
public class JpaClienteDao implements ClienteDao {

	@PersistenceContext
	private EntityManager em;

	@Transactional(propagation = Propagation.REQUIRED)
	public void insert(Cliente cliente) throws ErroBancoDados {
		try {
			em.persist(cliente);
			em.flush();
		} catch (PersistenceException e) {
			throw new ErroBancoDados("Ocorreu um erro ao adicionar cliente: "
					+ cliente, e);
		}
	}

	@Transactional(propagation = Propagation.REQUIRED)
	public void update(Cliente cliente) throws ErroBancoDados {
		try {
			em.merge(cliente);
			em.flush();
		} catch (PersistenceException e) {
			throw new ErroBancoDados("Ocorreu um erro ao atualizar cliente: "
					+ cliente, e);
		}
	}

	@Transactional(propagation = Propagation.REQUIRED)
	public void delete(Cliente cliente) throws ErroBancoDados {
		try {
			cliente.setRegistroAtivo(false);
			em.merge(cliente);
		} catch (PersistenceException e) {
			throw new ErroBancoDados("Ocorreu um erro ao deletar cliente: "
					+ cliente, e);
		}
	}

	@Override
	public Cliente select(int numero) throws ResultadoVazio {
		Cliente reference = em.find(Cliente.class, numero);

		if (reference == null) {
			throw new ResultadoVazio("Nao foi encontrado cliente de numero = "
					+ numero);
		}
		return reference;
	}

	@Override
	public List<Cliente> select(String nome) throws ResultadoVazio {
		TypedQuery<Cliente> query = em
				.createQuery(
						"SELECT DISTINCT OBJECT(c) FROM Cliente c WHERE (c.nomeFantasia LIKE :nome OR c.razaoSocial LIKE :nome) and c.registroAtivo=true",
						Cliente.class);
		query.setParameter("nome", "%" + nome + "%");
		List<Cliente> resultado = query.getResultList();

		if (resultado == null || resultado.isEmpty()) {
			throw new ResultadoVazio("Nao foi encontrado cliente com nome = "
					+ nome);
		}

		return resultado;
	}

	@Override
	public List<Cliente> select() throws ResultadoVazio {
		TypedQuery<Cliente> query = em
				.createQuery(
						"SELECT DISTINCT OBJECT(c) FROM Cliente c WHERE c.registroAtivo=true",
						Cliente.class);
		List<Cliente> resultado = query.getResultList();

		if (resultado == null || resultado.isEmpty()) {
			throw new ResultadoVazio(
					"Nao foi encontrado nenum registro de cliente ativo");
		}

		return resultado;
	}
}
